#!/usr/bin/env python
import asyncio
import websockets
import json
import uuid
import http.server
decoder = json.JSONDecoder()
encoder = json.JSONEncoder()
clients = []
channels = {}
class Channel:
    def __init__(self, host, url):
        self.page = None
        self.url = url
        self.clients = set()
        self.host = host
    async def add_client(self, client):
        self.clients.add(client)
        await client.send(encoder.encode({"type": "channel_info", "url": self.url, "page": self.page}))
    async def set_page(self, page):
        self.page = page
    async def broadcast(self, message):
        reqs = []
        for client in self.clients:
            try:
                reqs.append((client.send(message), client))
            except websockets.exceptions.ConnectionClosed as e:
                self.clients.remove(client)
        for req, client in reqs:
            try:
                await req
            except websockets.exceptions.ConnectionClosed as e:
                self.clients.remove(client)
async def ws_serve_one(websocket, path):
    clients.append(websocket)
    master = False
    channel = None
    async for message in websocket:
        # if message == "master":
        #     master = True
        msg = decoder.decode(message)
        print(msg)
        if msg["type"] == "channel":
            name = str(uuid.uuid1())
            url = msg["url"]
            if name not in channels:
                channel = Channel(websocket, url)
                channels[name] = channel

            await websocket.send(encoder.encode({"type": "channel_created", "name": name}))
        elif msg["type"] == "subscribe":
            name = msg["name"]
            if name in channels:
                await channels[name].add_client(websocket)
        elif msg["type"] == "page":
            page = int(msg["page"])
            await channel.set_page(page)
            await channel.broadcast(message)
        elif msg["type"] == "mousemove":
            if channel:
                await channel.broadcast(message)
def ws_get_server(host="localhost", port=8765):
    start_server = websockets.serve(ws_serve_one, host, port)
    evloop = asyncio.get_event_loop()
    def server():
        evloop.run_until_complete(start_server)
        evloop.run_forever()
    return server
def http_get_server(host="localhost", port=8000):
    server_address = (host, port)
    httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
    def server():
        httpd.serve_forever()
    return server
if __name__ == "__main__":
    import threading
    thrd_ws = threading.Thread(target=ws_get_server("localhost", 8765))
    thrd_http = threading.Thread(target=http_get_server("localhost", 8000))
    thrd_ws.start()
    thrd_http.start()
    thrd_ws.join()
    thrd_http.join()